package com.eystar.pdc.aop.auth;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.eystar.ext.kit.RequestKit;
import com.eystar.pdc.aop.auth.AuthAnno.AuthType;
import com.eystar.pdc.model.User;
import com.eystar.pdc.util.LoginUtil;
import com.eystar.pdc.util.PdcHelper;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.Ret;
import com.jfinal.log.Log;

import cn.hutool.core.util.StrUtil;

/**
 * 权限验证(判断方法是否可以访问，所有人都可以访问、只有权限验证后的登录用户才可以访问、只有超级管理员才可以访问)
 * @author auth
 *
 */
public class AuthInterceptor implements Interceptor {
	protected final Log logger = Log.getLog(AuthInterceptor.class);
	
	@Override
	public void intercept(Invocation ai) {
		Controller controller = ai.getController();
		// 1、判断authanno在类上还是方法上
		AuthAnno clazzAnno = null,methodAnno = null;
		if(controller.getClass().isAnnotationPresent(AuthAnno.class)){ // 如果类上有注释
			logger.info(controller.toString() + "进入类上的注解");
			clazzAnno = controller.getClass().getAnnotation(AuthAnno.class);
		}
		if (ai.getMethod().isAnnotationPresent(AuthAnno.class)) {
			logger.info(controller.toString() + "进入方法上的注解");
			methodAnno = ai.getMethod().getAnnotation(AuthAnno.class); // 如果方法上面有注释
		}
		
		// 2、如果类上面没有注解，根本不需要判断方法上面的注解，因为方法上的注解属性就一个auth()，方法是有此注释的前提是类上有此注释，直接进入方法内部
		if (clazzAnno == null) {
			ai.invoke();
			return;
		}
		// 下面的判断思路就是：如果方法上面是空，使用类上的注解；反之使用方法上的注解
		AuthType type = (methodAnno == null || methodAnno.type() == null) ? clazzAnno.type() : methodAnno.type();
		String res = (methodAnno == null || "".equals(methodAnno.res())) ? clazzAnno.res() : methodAnno.res();
		String menu =(methodAnno == null || "".equals(methodAnno.menu())) ? clazzAnno.menu() : methodAnno.menu();
		String auth = methodAnno == null ? clazzAnno.auth() : methodAnno.auth();
		String loginUrl = (methodAnno == null || "".equals(methodAnno.loginUrl())) ? clazzAnno.loginUrl() : methodAnno.loginUrl();
		if (StrUtil.isBlank(res) && StrUtil.isNotBlank(menu)) {
			res = menu;
		}else if(StrUtil.isBlank(menu) && StrUtil.isNotBlank(res)){
			menu = res;
		}
		HttpServletRequest request = controller.getRequest();
		// 将权限标识设置在request中
		request.setAttribute(LoginUtil.MENU_REMARK_NAME, menu);
		User user = (User) request.getSession().getAttribute(LoginUtil.SESSION_CURRENT_USER);
		// 如果需要验证，但是会话中没有用户
		if ((type.equals(AuthType.Auth) || type.equals(AuthType.Super)) && user == null) {
			toInfoJsp(ai.getController(), loginUrl);
		// 如果需要超级管理员但是登录用户不是超级超级管理员
		}else if (type.equals(AuthType.Super) && !PdcHelper.isSuper(request)) {
			// ----------- 应该往上抛一个异常
			throw new AuthException("需要超级管理员权限！");
		}else if (StrUtil.isNotBlank(res) && !PdcHelper.hasAuth(request, res + "_" + auth)) {
			throw new AuthException("方法无权操作！Tips = " + res + "_" + auth);
		}else {
			ai.invoke();
		}
	}

	private void toInfoJsp(Controller controller,String loginUrl) {
		HttpServletRequest request = controller.getRequest();
		String toPage = "";
		String msg = "";
		if (StrUtil.isNotBlank(loginUrl)) {
			toPage = request.getContextPath() + loginUrl;
			msg = "您还没有登录，请先登录！";
		}
		HttpSession session = request.getSession();
		session.setAttribute("msg", msg);
		if (RequestKit.isAjaxRequest(controller.getRequest())) {
			controller.renderJson(Ret.fail("msg","您还没有登录，请先登录！"));
		}else {
			controller.renderHtml("<script>top.location.href='" + toPage + "';</script>");
		}
	}
}
